﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Linq;
using DevExpress.XtraEditors;
using DevExpress.XtraLayout.Utils;
using PRO_DOCS.DAL.Database;
using PRO_DOCS.DocumentManagementSystem.Petrolium.WIN._7z;


namespace PRO_DOCS.DocumentManagementSystem.Petrolium.WIN.Back
{
    public partial class BackupSettings : BLL.WIN.Templates.DevxPermissionUserControlTemplate
    {
        public static void WriteToEventLog(string message)
        {
            var cs = "PRO-DOC";
            var elog = new EventLog();

            if (!EventLog.SourceExists(cs))
            {
                EventLog.CreateEventSource(cs, cs);
            }

            elog.Source = cs;
            elog.EnableRaisingEvents = true;
            elog.WriteEntry(message, EventLogEntryType.Error);
        }

        public BackupSettings()
        {
            InitializeComponent();

            #region event log

            WriteToEventLog("Backup Prog Started");

            #endregion

            var showItm = new MenuItem("Show Settings");
            showItm.Click += new EventHandler(showItm_Click);
            var closeItm = new MenuItem("Close App");
            closeItm.Click += new EventHandler(closeItm_Click);

            var men = new ContextMenu(new[] { showItm, closeItm });
            myNotifyIcon.ContextMenu = men;
        }

        //private string GetSettingVal(string key)
        //{
        //    var reader = new AppSettingsReader();
        //    return ((string)reader.GetValue(key, typeof(string)));
        //}

        void closeItm_Click(object sender, EventArgs e)
        {
            Environment.Exit(0);
        }

        void showItm_Click(object sender, EventArgs e)
        {
            _setVisable = true;
            this.Show();
        }

        private void addButton_Click(object sender, System.EventArgs e)
        {
            using (var frm = new Schedule(-1))
            {
                if (frm.ShowDialog(this) == DialogResult.OK)
                {
                    LoadTasks();
                    if (frm.IsNow)
                    {
                        StartTask(distTextEdit.Text, null, frm.storageComboBoxEdit.Text, true);
                    }
                }
            }
        }

        private void LoadTasks()
        {
            gridControl1.DataSource = null;
            gridControl1.DataSource = PRO_DOCSDatabaseDataContext.proc_BackUp_TasksLoad(-1).ToList();
            distTextEdit.Text = PRO_DOCSDatabaseDataContext.CustomSettingsSelect().First().Dist;
        }

        private void updateButton_Click(object sender, System.EventArgs e)
        {
            var selected = gridView1.GetRow(gridView1.FocusedRowHandle) as proc_BackUp_TasksLoadResult;
            if (selected != null)
            {
                using (var frm = new Schedule(selected.TaskID))
                {
                    if (frm.ShowDialog(this) == DialogResult.OK)
                    {
                        LoadTasks();
                        if (frm.IsNow)
                        {
                            StartTask(distTextEdit.Text, selected.TaskID.ToString(), frm.storageComboBoxEdit.Text, true);
                        }
                    }
                }
            }
            else
            {
                XtraMessageBox.Show("Please Select the task first");
            }
        }


        private delegate void FlusherStartTasks();
        private void FinishWorking(IAsyncResult result)
        {
            var flusher = (FlusherStartTasks)result.AsyncState;
            flusher.EndInvoke(result);
            //hide the waiting
        }

        private void StartCheck()
        {
            try
            {
                //set ui lock
                _working = true;

                var res =
                    PRO_DOCSDatabaseDataContext.proc_BackUp_TasksLoad(-1).Where(
                        n =>
                        (n.IsActive != null && n.IsActive.Value) &&
                        (string.IsNullOrEmpty(n.CurrentState) || n.CurrentState != "Done")).ToList();


                foreach (proc_BackUp_TasksLoadResult tasksLoadResult in res)
                {
                    var hist = PRO_DOCSDatabaseDataContext.BackUp_Tasks_History_Select(tasksLoadResult.TaskID).ToList();

                    if (tasksLoadResult.TaskType == "Once")
                    {
                        StartTask(distTextEdit.Text, tasksLoadResult.TaskID.ToString(), tasksLoadResult.StorageType, false);
                    }
                    else if (tasksLoadResult.TaskType == "Daily")
                    {
                        if (hist.Count > 0)
                        {
                            if (
                                !hist.Any(
                                    a =>
                                    a.State == "Done" && a.Date.HasValue &&
                                    a.Date.Value.ToString("dd-MM-yyyy") == DateTime.Now.ToString("dd-MM-yyyy")))
                            {
                                if (tasksLoadResult.TaskStartAt != null &&
                                    long.Parse(tasksLoadResult.TaskStartAt.Value.ToString("HHmmss")) <
                                    long.Parse(DateTime.Now.ToString("HHmmss")))
                                    StartTask(distTextEdit.Text, tasksLoadResult.TaskID.ToString(), tasksLoadResult.StorageType, false);
                            }
                        }
                        else
                        {
                            if (tasksLoadResult.TaskStartAt != null &&
                                    long.Parse(tasksLoadResult.TaskStartAt.Value.ToString("HHmmss")) <
                                    long.Parse(DateTime.Now.ToString("HHmmss")))
                                StartTask(distTextEdit.Text, tasksLoadResult.TaskID.ToString(), tasksLoadResult.StorageType, false);
                        }
                    }
                    else if (tasksLoadResult.TaskType == "Weekly")
                    {
                        if (hist.Count > 0)
                        {
                            if (
                                !hist.Any(
                                    a =>
                                    a.State == "Done" && a.Date.HasValue &&
                                    a.Date.Value.ToString("dd-MM-yyyy") == DateTime.Now.ToString("dd-MM-yyyy")))
                            {
                                if (tasksLoadResult.TaskStartAt != null &&
                                    long.Parse(tasksLoadResult.TaskStartAt.Value.ToString("HHmmss")) <
                                    long.Parse(DateTime.Now.ToString("HHmmss")) &&
                                    tasksLoadResult.RepeatDayes.Split(';').Any(m => m.ToString() == DateTime.Now.DayOfWeek.ToString()))
                                    StartTask(distTextEdit.Text, tasksLoadResult.TaskID.ToString(), tasksLoadResult.StorageType, false);
                            }
                        }
                        else
                        {
                            if (tasksLoadResult.TaskStartAt != null &&
                                    long.Parse(tasksLoadResult.TaskStartAt.Value.ToString("HHmmss")) <
                                    long.Parse(DateTime.Now.ToString("HHmmss")) &&
                                    tasksLoadResult.RepeatDayes.Split(';').Any(m => m.ToString() == DateTime.Now.DayOfWeek.ToString()))
                                StartTask(distTextEdit.Text, tasksLoadResult.TaskID.ToString(), tasksLoadResult.StorageType, false);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                WriteToEventLog(ex.ToString());
            }
            finally
            {
                _working = false;
            }
        }

        private bool _working = false;
        private void StartTask(string backLocationDist, string taskID, string storageMedia, bool isNow)
        {

            try
            {

                string errorMsg = string.Empty;

                var setting = PRO_DOCSDatabaseDataContext.CustomSettingsSelect().First();

                string current_pathes_sources = string.Empty;

                List<DAL.Database.ARCHIVE_DEPARTMENTS_STORAGES_HEIRARCHY_PHYSICAL_PATHE> physicalPathes = PRO_DOCSDatabaseDataContext.ARCHIVE_DEPARTMENTS_STORAGES_HEIRARCHY_PHYSICAL_PATHEs.ToList();

                var settingID = setting.SettingID.ToString();


                var dist = Path.Combine(backLocationDist, settingID, DateTime.Now.ToString("yyyy-MM-dd"),
                                        taskID ?? Guid.NewGuid().ToString());
                if (!Directory.Exists(dist))
                    Directory.CreateDirectory(dist);


                if (taskID != null)
                    PRO_DOCSDatabaseDataContext.proc_BackUp_Tasks_UpdateCurrentState(taskID, "Working");

                var dbDist = Path.Combine(dist, Guid.NewGuid() + "");


                BackAndRestore.BackUp.BackupDatabase(PRO_DOCSDatabaseDataContext.Connection.DataSource, PRO_DOCSDatabaseDataContext.Connection.Database, dbDist + ".bak",
                                                     storageMedia.ToLower() == "tape");


                string directoryName = System.Reflection.Assembly.GetExecutingAssembly().Location;

                Zipping.Compress(PRO_DOCS.DocumentManagementSystem.Petrolium.WIN.Properties.Settings.Default.zPath, dbDist + ".bak", dbDist + "_db",
                                 setting.ZippingCommand);


                File.Delete(dbDist + ".bak");



                for (int i = 0; i < physicalPathes.Count; i++)
                {
                    var distFiles = Path.Combine(dist, Guid.NewGuid().ToString() + "_file");

                    string src = physicalPathes[i].ARCHIVE_DEPARTMENTS_STORAGES_HEIRARCHY_PHYSICAL_PATH;

                    if (new DirectoryInfo(src).Exists)
                    {
                        Zipping.Compress(PRO_DOCS.DocumentManagementSystem.Petrolium.WIN.Properties.Settings.Default.zPath, src, distFiles, setting.ZippingCommand);
                    }
                }


                if (taskID != null && PRO_DOCSDatabaseDataContext.proc_BackUp_TasksLoad(int.Parse(taskID)).First().TaskType == "Once")
                    PRO_DOCSDatabaseDataContext.proc_BackUp_Tasks_UpdateCurrentState(taskID, "Done");

                if (taskID != null)
                    PRO_DOCSDatabaseDataContext.BackUp_Tasks_History_Add(int.Parse(taskID), "Done", DateTime.Now, "");
                if (isNow)
                    XtraMessageBox.Show("Done");
            }
            catch (Exception ex)
            {
                WriteToEventLog(ex.ToString());
                if (taskID != null)
                {
                    PRO_DOCSDatabaseDataContext.proc_BackUp_Tasks_UpdateCurrentState(taskID, "Faild see the log");
                    PRO_DOCSDatabaseDataContext.BackUp_Tasks_History_Add(int.Parse(taskID), "Failed", DateTime.Now,
                        "See the log:" + ex.ToString());
                }
                if (isNow)
                    XtraMessageBox.Show("False");
            }
        }

        private void zipSettingsButton_Click(object sender, EventArgs e)
        {
            using (var frm = new ZippingSettings())
            {
                if (frm.ShowDialog(this) == DialogResult.OK)
                {
                    var res = PRO_DOCSDatabaseDataContext.CustomSettings_UpdateBackupCommand(frm.ZipCommand, frm.UnZipCommand);
                    XtraMessageBox.Show(res == 0 ? "Saved Successfuly" : "Faild To Save");
                }
            }
        }

        private void Backup_Load(object sender, EventArgs e)
        {
            dbNameTextEdit.Text = PRO_DOCSDatabaseDataContext.Connection.Database + "_";
            LoadTasks();
            //this.Hide();
        }

        private void Backup_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            this.Hide();
            myNotifyIcon.ShowBalloonTip(9000);
        }

        private bool _setVisable = false;
        private void Backup_VisibleChanged(object sender, EventArgs e)
        {
            if (!_setVisable)
                this.Hide();
        }

        private void myTimer_Tick(object sender, EventArgs e)
        {
            if (!_working)
            {
                var flusher = new FlusherStartTasks(StartCheck);
                flusher.BeginInvoke(FinishWorking, flusher);
            }
            else
            {
                //show wait
            }
        }

        private void myNotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            showItm_Click(null, null);
        }

        private void operationTypeComboBoxEdit_SelectedIndexChanged(object sender, EventArgs e)
        {
            distTextEdit.ResetText();

            if (operationTypeComboBoxEdit.SelectedIndex == 0)
            {
                layoutControlItem4.Visibility = layoutControlItem6.Visibility = LayoutVisibility.Always;
                layoutControlItem8.Visibility = layoutControlItem12.Visibility = LayoutVisibility.Never;
            }
            else
            {
                layoutControlItem4.Visibility = layoutControlItem6.Visibility = LayoutVisibility.Never;
                layoutControlItem8.Visibility = layoutControlItem12.Visibility = LayoutVisibility.Always;
            }
        }

        private void startRestoreButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (XtraMessageBox.Show("Please Be Carful You Can't Rollback this operation", "PR-DOC", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
                    return;

                if (!dbNameTextEdit.Text.Contains(PRO_DOCSDatabaseDataContext.Connection.Database + "_") ||
                        dbNameTextEdit.Text.ToLower() == (PRO_DOCSDatabaseDataContext.Connection.Database + "_").ToLower())
                {
                    XtraMessageBox.Show("Database name not valid");
                    return;
                }

                if (GetAllDatabasesOnServer().Contains(dbNameTextEdit.Text.ToLower()))
                {
                    XtraMessageBox.Show("This db name is already exists on server");
                    return;
                }


                if (!string.IsNullOrEmpty(srcTextEdit.Text))
                {
                    if (srcTextEdit.Text.IndexOf(";", System.StringComparison.OrdinalIgnoreCase) != -1)
                    {
                        var setting = PRO_DOCSDatabaseDataContext.CustomSettingsSelect().First();

                        if (srcTextEdit.Text.Split(';').Any(a => !new FileInfo(a).Exists))
                        {
                            XtraMessageBox.Show("One or more source pathes not exist");
                            return;
                        }

                        var dbFile = srcTextEdit.Text.Split(';').FirstOrDefault(
                            a => new FileInfo(a).Name.IndexOf("_db", StringComparison.OrdinalIgnoreCase) != -1);
                        var filesFile = srcTextEdit.Text.Split(';').FirstOrDefault(
                            a => new FileInfo(a).Name.IndexOf("_file", StringComparison.OrdinalIgnoreCase) != -1);
                        if (dbFile != null)
                        {
                            var tempDir = Path.Combine(Path.GetTempPath(), "PRO_Codes");

                            if (!new DirectoryInfo(tempDir).Exists)
                                Directory.CreateDirectory(tempDir);


                            var res1 =
                                _7z.Zipping.ExtractWithCommand(PRO_DOCS.DocumentManagementSystem.Petrolium.WIN.Properties.Settings.Default.zPath,
                                                               dbFile,
                                                               tempDir, setting.UnZippingCommand);

                            var resFiles = Directory.GetFiles(tempDir);
                            if (resFiles.Any())
                            {
                                var dbFileName = resFiles[0];
                                if (res1 == "No error")
                                {
                                    if (!restoreDBCheckEdit.Checked)
                                    {
                                        File.Copy(dbFileName,
                                            Path.Combine(distTextEdit.Text, new FileInfo(dbFileName).Name));
                                        XtraMessageBox.Show("Successfuly Done extracted the DB file to {" +
                                                            new FileInfo(dbFileName).Name + "}");

                                    }
                                    else
                                    {

                                        var res2 =
                                            BackAndRestore.BackUp.Restore(
                                                PRO_DOCSDatabaseDataContext.Connection.DataSource,
                                                dbNameTextEdit.Text,
                                                dbFileName,
                                                PRO_DOCSDatabaseDataContext.Connection.ConnectionString,
                                                storageTypeComboBoxEdit.Text.ToLower() == "tape");
                                        XtraMessageBox.Show(res2 ? "Successfuly Done the DB Restore" : "Error");
                                    }
                                    foreach (string s in resFiles)
                                        File.Delete(s);
                                }
                                else
                                {
                                    XtraMessageBox.Show("The db file can't e extraced or not exist");
                                }
                            }
                            else
                            {
                                XtraMessageBox.Show("The db file can't e extraced or not exist");
                            }
                        }
                        else
                        {
                            XtraMessageBox.Show("The db file not exist");
                        }

                        if (filesFile != null)
                        {
                            if (!string.IsNullOrEmpty(distTextEdit.Text) &&
                                new DirectoryInfo(distTextEdit.Text).Exists)
                            {

                                var res =
                                    _7z.Zipping.ExtractWithCommand(PRO_DOCS.DocumentManagementSystem.Petrolium.WIN.Properties.Settings.Default.zPath,
                                                                   filesFile,
                                                                   distTextEdit.Text, setting.UnZippingCommand);
                                XtraMessageBox.Show(res != "No error"
                                                        ? res
                                                        : "Successfuly Done the Files Restore");
                            }
                        }
                    }
                    else
                    {
                        if (new FileInfo(srcTextEdit.Text).Name.IndexOf("_db", StringComparison.OrdinalIgnoreCase) != -1)
                        {
                            var res =
                              BackAndRestore.BackUp.Restore(
                                  PRO_DOCSDatabaseDataContext.Connection.DataSource,
                                  PRO_DOCSDatabaseDataContext.Connection.Database,
                                  srcTextEdit.Text,
                                  PRO_DOCSDatabaseDataContext.Connection.ConnectionString,
                                  storageTypeComboBoxEdit.Text.ToLower() == "tape");
                            XtraMessageBox.Show(res ? "Successfuly Done the DB Restore" : "Error");
                        }

                        if (new FileInfo(srcTextEdit.Text).Name.IndexOf("_file", StringComparison.OrdinalIgnoreCase) != -1)
                        {
                            if (!string.IsNullOrEmpty(distTextEdit.Text) &&
                               new DirectoryInfo(distTextEdit.Text).Exists)
                            {
                                var setting = PRO_DOCSDatabaseDataContext.CustomSettingsSelect().First();
                                var res =
                                    _7z.Zipping.ExtractWithCommand(PRO_DOCS.DocumentManagementSystem.Petrolium.WIN.Properties.Settings.Default.zPath,
                                                                   srcTextEdit.Text,
                                                                   distTextEdit.Text, setting.UnZippingCommand);
                                XtraMessageBox.Show(res != "No error"
                                                        ? res
                                                        : "Successfuly Done the Files Restore");
                            }
                        }
                    }
                }
                else
                {
                    XtraMessageBox.Show("Please check that the Source path is exist");
                }
            }
            catch (Exception ex)
            {
                WriteToEventLog(ex.ToString());
            }
        }


        private void browseSrcButton_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog(this) == DialogResult.OK)
            {
                srcTextEdit.Text = string.Join(";", openFileDialog1.FileNames);
            }
        }

        private void browseDistButton_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog(this) == DialogResult.OK)
            {
                distTextEdit.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        private void dbNameTextEdit_EditValueChanging(object sender, DevExpress.XtraEditors.Controls.ChangingEventArgs e)
        {
            if (!e.NewValue.ToString().Contains(PRO_DOCSDatabaseDataContext.Connection.Database + "_"))
            {
                e.Cancel = true;
                XtraMessageBox.Show("You can't Change the db Name formate");
                return;
            }
        }


        private List<string> GetAllDatabasesOnServer()
        {
            var databases = new List<string>();
            try
            {
                var sqlConn = new SqlConnection(PRO_DOCSDatabaseDataContext.Connection.ConnectionString);
                //open connection
                sqlConn.Open();
                //get databases
                DataTable tblDatabases = sqlConn.GetSchema("Databases");
                //close connection
                sqlConn.Close();

                //add to list
                databases.AddRange(from DataRow row in tblDatabases.Rows
                                   select row["database_name"].ToString().ToLower());
            }
            catch (Exception ex)
            {
                Back.Backup.WriteToEventLog(ex.ToString());
                return null;
            }
            return databases;
        }

    }
}